home *** CD-ROM | disk | FTP | other *** search
- // voxel demo
- //
- // 95-03-Sep.
- // jeff bilger
- // eusjeb@exu.ericsson.se
- // (Send me email if you have any comments)
- //
- // *********************
- // * Overview *
- // *********************
- // This program will
- // generate a voxel terrain map and place this data in a 2d array
- // rotate the terrain map data about x,y,z
- // sort the voxel terrain map data by z (small values)
- // finally display the voxel map to the crt.
- // A virtual window can be defined, see the #define section
- //
- // *********************
- // * History *
- // *********************
- // uses quick sort
- // added a period, and a granularity input,
- // the gen_map fnct uses these vars to compute the voxel map
- // - added rotations about all 3 axes.
- // - removed temp[][] array. No need to copy WIDTH*HEIGHT*3 words
- // per display anymore.
- // - added angle incr settings
- // - color is indep. of height once transformations occur.
- // the color is only dependent on the *original* heght now
- // - added logic to clip at the crt window
- // - optimized for speed (rotate/display)
- //
- //
- //
-
- #include <dos.h>
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <conio.h>
- #include "..\library\grafix.h"
-
-
- /**********************/
- /* Function Prototypes*/
- /**********************************************************************/
- void main();
- void init();
- void build_palette();
- void display_();
- void draw_voxel(int,int,int,int);
- void gen_map();
- void rotate(double);
- void _qsort(int,int);
- void swap(int,int);
-
-
- /*********/
- /*Defines*/
- /**********************************************************************/
-
- #define DEPTH 20 // depth of the terrain map (z)
- #define WIDTH 40 // width of the terrain map (x)
- #define X_ORIGIN 100 // x,y origin of the screen
- #define Y_ORIGIN 100
- #define MAX_HEIGHT 50.0 // max height of the terrain
- #define INITIAL_HEIGHT 5 // initial height of the terrain
- #define PI 3.1415
- #define NO 0
- #define YES 1
- #define XW_MIN 10 // coords that define the 'virtual'
- #define XW_MAX 300 // window on the crt
- #define YW_MIN 5
- #define YW_MAX 190
-
-
- /***************/
- /* Structures */
- /********************************************************************/
-
- struct pts // structure for terrain map data
- {
- float x,y,z,color;
- };
- typedef struct pts TERRAIN_POINTS;
-
- struct pts_int // structure for display map data
- {
- int x,y,z,color;
- };
- typedef struct pts_int DISPLAY_POINTS;
-
-
- TERRAIN_POINTS map[DEPTH][WIDTH]; // holds original terrain coords
- DISPLAY_POINTS display[DEPTH*WIDTH]; // holds coords to display on the
- // crt after transformations and
- // sorting
-
-
-
- /***********/
- /* Globals */
- /*****************************************************************/
-
- char far *SCR; // ptrs to video memory
- char *BACK; // and our double buffer
- unsigned char PAL[256*3]; // 256 colors (rgb) for the palette
- float PERIOD, // user defined period
- COS_10, // for roataions
- SIN_10;
- int GRANULARITY, // user defined size of voxel
- THETA_INCR; // user defined angle increment for rotations
- char CLIPPING = NO; // clipping flag
-
-
-
-
- /**************/
- /* Main() */
- /********************************************************************/
-
- void main()
- {
- double theta; // holds current angle
- int i=0; // counter
-
-
- /***************************/
- /* Get user defined params.*/
- /***************************/
- printf("-Voxel landscape demo by Jeff Bilger (eusjeb@exu.ericsson.se)-\n");
- printf("Enter the period: (90,180,360 etc) (530 is a good value):");
- scanf("%f",&PERIOD);
- printf("Enter the length of the voxel sides: (1,2,3 etc) (2 is a good value):");
- scanf("%d",&GRANULARITY);
- printf("Enter the degree increment per rotation: (8 is a good value):");
- scanf("%d",&THETA_INCR);
-
-
-
- /*******************************/
- /* Do some initialization stuff*/
- /*******************************/
- init();
-
-
- /****************/
- /* Main routine */
- /****************/
- while (!kbhit()) // loop until user hits a key
- {
- for(i=1;i<360;i+=THETA_INCR) // For each iteration...
- {
- theta = (double)i * PI / 180.0; // convert current angle to radians
-
- rotate(theta); // rotate map and save to 1d display array
- _qsort(0,DEPTH*WIDTH-1); // sort it
- display_(); // save it to double buffer
- G_WaitRetrace();
- G_memcpy_word(SCR,BACK,320*200/2); // display it to the crt
- G_Set_screen_color(0,BACK); // erase the double buffer and repeat..
- }
-
- theta = 0.0; // if a full 360 degree revolution has
- // finished, reset the angle and repeat...
- }
- G_Text_mode(); // Go back to text mode
-
- } // end of main()
-
- /*******************************************************************/
- /*******************************************************************/
-
-
-
-
-
- /************************/
- /* Procedures/Functions */
- /*******************************************************************/
-
- // [%]===========================[%]
- // [%]build palette [%]
- // [%]===========================[%]
- //
- // This procedure will generate the palette that will be used
- // to display the voxel terrain.
- //
- // In video mode 13h, the PC can display 256 colors from the palette
- // The palette has 256 entries and each entry is defined by a RGB color
- // value. The RGB value is 18 bits long thus 6 bits are used
- // for the R component, 6 bits for the G comp. and 6 bits for the B comp.
- // Thus each component can have a max value of 64 (2^6 = 64)
- //
- // The palette will be built such that whites/light greens are in the
- // lower color entries and dark greens are in the higher entries
- void build_palette()
- {
- int i;
- int r=63,g=63,b=63; // for palette setting
-
- PAL[0]= 0; // 1st pal entry is the background, we cant that
- PAL[1]=0; // to be BLACK (rgb = 0,0,0)
- PAL[2]=0;
-
-
- for(i=3;i<52*3;i+=3) // set next 52 color entries
- {
- PAL[i] = r;
- PAL[i+1] = g;
- PAL[i+2] = b;
- if(i%9==0) { r--;g--;b--;}
- }
-
-
- g=63;
- for(;i<256*3;i+=3) // set the rest of the color entries
- {
- PAL[i] = 0;
- PAL[i+1] = g--;
- PAL[i+2] = 0;
- }
-
- }
-
-
-
-
- // [%]===========================[%]
- // [%]init [%]
- // [%]===========================[%]
- //
- // Just set up some stuff
- void init()
- {
- SCR = (char far *) MK_FP(0xa000,0); // setup addr to video memory
- BACK =(char *) malloc(64000); // alloc memory for double buffer
- if(BACK == NULL) exit(0);
-
- COS_10 = cos(10.0*PI/180.0); // for use in rotations
- SIN_10 = sin(10.0*PI/180.0);
-
- G_Int13_mode(); // enter video mode 13h
- build_palette(); // build the palette
- G_SetPal(PAL,0,256); // assign the new palette
- gen_map(); // build terrain map
-
- }
-
-
-
-
-
- // [%]===========================[%]
- // [%]display [%]
- // [%]===========================[%]
- //
- // This procedure will draw the voxel landscape.
- // The array 'display[]' contains the *sorted* voxel landscape
- // data, it is sorted by z such that small z values occur first. Thus
- // we will draw from 'display[DEPTH * width - 1] to [0]' or back to front
- void display_()
- {
- int i,x1,y1,x2;
-
- for(i=DEPTH*WIDTH -1 ;i>=0;i--)
- {
- x1 = display[i].x-GRANULARITY; // define the length of the voxel
- y1 = display[i].y-GRANULARITY;
- x2 = display[i].x+GRANULARITY;
-
- // see if any clipping needs to be
- // done
- if (x1 < XW_MIN || x2 > XW_MAX || y1 < YW_MIN || y1+10 > YW_MAX)
- CLIPPING = YES;
-
-
- draw_voxel(x1,y1,x2, display[i].color);
-
- }
- }
-
-
-
- // [%]===========================[%]
- // [%]draw_voxel [%]
- // [%]===========================[%]
- //
- // draw the voxel
- void draw_voxel(int x1,int y1, int x2, int c)
- {
- int x=x1;
- int offset = y1*320;
- int loop;
-
- if ( !CLIPPING)
- while(x++ <= x2)
- {
- *(BACK + (offset + x)) = c; // all voxels will be 10 pixels
- *(BACK + (offset + 320) + x) = c; // high
- *(BACK + (offset + 2*320) + x) = c;
- *(BACK + (offset + 3*320) + x) = c;
- *(BACK + (offset + 4*320) + x) = c;
- *(BACK + (offset + 5*320) + x) = c;
- *(BACK + (offset + 6*320) + x) = c;
- *(BACK + (offset + 7*320) + x) = c;
- *(BACK + (offset + 8*320) + x) = c;
- *(BACK + (offset + 9*320) + x) = c;
- }
-
- else // CLIPPING is needed
- {
- loop = y1+10; // each voxel is usually 10 pixels high
-
- if (x < XW_MIN) x=XW_MIN; // case 1,
- else if (x2 > XW_MAX) x2=XW_MAX; // if case 1 is True, case 2
- // can *never* be true unless you
- // defined GRANULARITY as some
- // value that is larger than
- // the width of your virtual window
- // which would be stupid.
-
- if (y1 < YW_MIN) // case 3
- {
- loop = (10 + y1);
- y1 = YW_MIN;
- }
- else if ((y1 + 10) > YW_MAX) // case 4 can never be true if case 3
- loop = YW_MAX; // is true unless you define your
- // virtual window height as less than 10
- // (again, stupid..)
-
- for( ; y1<loop ; y1++) // draw the clipped voxel
- while(x++ <= x2)
- *(BACK + (y1*320 + x)) = c;
- CLIPPING = NO; // turn clipping off
- }
- }
-
-
-
-
-
- // [%]===========================[%]
- // [%]gen_map [%]
- // [%]===========================[%]
- //
- //
- // generates terrain using the sine function, this gives a 'hill-type'
- // effect
-
- void gen_map()
- {
- int i=0,j=0,xincr=0,zincr=0;
- double height_incr = MAX_HEIGHT / ( (float)DEPTH / 2),
- theta_incr = PERIOD / (float)WIDTH,
- height=INITIAL_HEIGHT,
- theta=0;
- int lastindex = DEPTH - 1; // point to last array index
- int MAX_Z = GRANULARITY*DEPTH;
-
- for (i=0;i<DEPTH/2;i++) // generate it symmetrically (both back and front)
- { // at the same time.
- for (j=0;j<WIDTH;j++)
- { // generate front side of the terrain
- map[i][j].x = xincr+=GRANULARITY;
- map[i][j].z = zincr;
- map[i][j].y = height * sin(theta * PI / 180.0);
- map[i][j].color =Y_ORIGIN - map[i][j].y; // set color the val of initial height
-
-
-
- // generate back side of the terrain
- map[lastindex-i][j].x = xincr+=GRANULARITY;
- map[lastindex-i][j].z = MAX_Z;
- map[lastindex-i][j].y = height * sin(theta * PI / 180.0);
- map[lastindex-i][j].color = Y_ORIGIN - map[lastindex-i][j].y; // set color the val of initial height
-
-
-
- theta += theta_incr;
-
- // printf("item[%d][%d] -- x =%f, z =%f , height=%f\n",i,j,map[i][j].x,map[i][j].z,map[i][j].y);
- }
- xincr=0; // reset x increment
- zincr+=GRANULARITY; // increment front z
- MAX_Z-=GRANULARITY; // decrement back z
- height += height_incr; // incr. the height
- theta =0;
- }
- }
-
-
-
-
-
- // [%]===========================[%]
- // [%]rotate [%]
- // [%]===========================[%]
- //
- // Rotate the voxel landscape
- //
- // theta is in radians
- // rotates about x,y,z
- //
- void rotate(double theta)
- {
- int i,j,k=0;
- float x,y,z;
- float tx,ty,tz; // for temp storage of rotated points
- float cos_ = cos(theta), // Rotation about y is the only roataion
- sin_ = sin(theta); // that depends on the current degree (in theta)
- // Rotation about x and z are always fixed at 10
- // degrees
-
- for(i=0;i<DEPTH;i++) // rotate for every voxel
- for(j=0;j<WIDTH;j++)
- {
- /* rotate about y */
- x = (float)map[i][j].x * cos_ + (float)map[i][j].z * sin_;
- z = -(float)map[i][j].x * sin_ + (float)map[i][j].z * cos_;
- tx = x;
-
- /* rotate about z */
- x = tx * COS_10 - (float)map[i][j].y * SIN_10;
- y = tx * SIN_10 + (float)map[i][j].y * COS_10;
-
- ty=y;
- tz=z;
-
- /* rotate about x */
- y = ty * COS_10 - tz * SIN_10;
- z = ty * SIN_10 + tz * COS_10;
-
- // printf("theta:%f x:%f z:%f cos(%f)=%f\n",theta,x,z,theta,cos(theta));
-
- //save transformed coords into 1 d array
-
- display[k].x = x + X_ORIGIN;
- display[k].y = Y_ORIGIN - y; // flip the image
- display[k].z = z + 50;
- display[k].color = map[i][j].color; // save the color
- k++;
- }
-
- }
-
-
-
-
-
- // [%]===========================[%]
- // [%]qsort [%]
- // [%]===========================[%]
- // sorts lowest z to highest z
- void _qsort(int l, int r)
- {
- int j,k;
-
- if (l < r)
- {
- if(display[l].z > display[r].z)
- swap(l,r);
- j=l;k=r;
- do
- {
- do{ j++; }while(display[j].z < display[l].z);
- do{ k--; }while(display[k].z > display[l].z);
- if (j<k) swap(j,k);
- }while(j<=k);
- swap(l,k);
- _qsort(l,k-1);
- _qsort(k+1,r);
- }
- }
-
-
- // [%]===========================[%]
- // [%]swap [%]
- // [%]===========================[%]
- //
- // used to swap points in the qsort function
- void swap(int l,int r)
- {
- DISPLAY_POINTS t;
-
- t.x = display[l].x; // save point
- t.y = display[l].y;
- t.z = display[l].z;
- t.color = display[l].color;
-
- display[l].x = display[r].x; // do swap
- display[l].y = display[r].y;
- display[l].z = display[r].z;
- display[l].color = display[r].color;
-
- display[r].x = t.x;
- display[r].y = t.y;
- display[r].z = t.z;
- display[r].color = t.color;
- }
-
-
-
-
-
-
-